#include "Expr.h"
#include "Number.h"
#include "Sym.h"
#include "Pow.h"
#include "Mul.h"
#include "Add.h"
#include "Fx.h"
#include "functions.h"
#include "ComparerIx.h"
#include "operators.h"
#include "Utilities.h"
#include "Substitution.h"
namespace sympycpp {
const Expr::Expr pi("pi");

Ex * Expr::innerCopy() const { 
	return e_->copy();
}
void Expr::setPrecision(const int i) {
	Number::setPrecision(i);
}
int Expr::getPrecision() {
	return Number::getPrecision();
}
Expr::Expr(const double i ) {
	e_ = new Number(i);
}
Expr::Expr(const int i,const char * number) {
	e_ = new Number(i, number);
}
Expr::Expr(const std::string & name ) {
	e_ = new Sym(name);
}

Expr::Expr(const char * name ) {
	std::string n(name);
	e_ = new Sym(n);
}
Expr::Expr(const int i) {
	e_ = new Number(i);
}
bool Expr::expansion(const int level) {
	return Utilities::expansion(e_, level);
}
Expr::Expr(const Expr & e) {
	e_ = e.e_->copy();
}
Expr::Expr(Ex * & e, const allocationPolicy i) {
	e_ = e;
	e = 0;
}
Expr::Expr(const Ex * e) {
	e_ = e->copy();
}
Expr::~Expr(){
	delete e_;
}
std::string Expr::tree() const {
	return e_->treeView(0);
}
void Expr::sub(const Expr & from, const Expr & to) {
	Substitution::sub(e_, from.e_, to.e_);
}
void Expr::sign(const Sign & z) {
	e_->sign(z);
}
Sign Expr::sign() const {
	return e_->sign();
}
std::string Expr::str() const {
	if (e_->isNum() && (!e_->sign() || !e_->isInteger())) {
		return ((Number *)e_)->str2();
	}
	return e_->str();
}
Expr Expr::taylorSeries(const Expr & byVar, const Expr & val, const int number) const {
	Ex * series = 0;
	Utilities::taylor(e_, series, (Sym *)byVar.e_, val.e_, number);
	return Expr(series, STEALING); 
}
const Expr & Expr::operator=(const Expr & x) {
	delete e_;
	e_ = x.e_->copy();
	return *this;
}
Expr & Expr::diff(const Expr & x) {
		if (!x.e_->isSym()) {
			return *this;
		}	
		Ex * e = e_->diff(*(Sym *)x.e_);
		delete e_;
		e_ = e;
		return *this;
}
Expr Expr::operator-() const {
	Expr e(*this);
	e.sign(!sign());
	return e;
}
Expr operator+(const Expr & L, const Expr & R) {
	return Operations::operatorAdd(L, R);
}
Expr operator-(const Expr & L, const Expr & R) {
	return Operations::operatorSub(L, R);
}
Expr operator*(const Expr & L, const Expr & R) {
	return Operations::operatorMul(L, R);
}
Expr Power(const Expr & base, const Expr & exponent) {
	return Operations::operatorPow(base, exponent);
}
Expr operator^(const Expr & base, const Expr & exponent) {
	return Operations::operatorPow(base, exponent);
}
Expr operator/(const Expr & L, const Expr & R) {
	return Operations::operatorDiv(L, R);
}
}
